// -----------------------------------------------------------------------
//  <copyright file="PcmStreamSourceFactory.cs" company="Henric Jungheim">
//  Copyright (c) 2012-2015.
//  <author>Henric Jungheim</author>
//  </copyright>
// -----------------------------------------------------------------------
// Copyright (c) 2012-2015 Henric Jungheim <software@henric.org>
// 
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;

namespace SM.Media.Audio.Generator
{
    public class PcmStreamSourceFactory<TMediaStreamSource> : GeneratorStreamSourceFactoryBase<TMediaStreamSource>
        where TMediaStreamSource : class
    {
        public PcmStreamSourceFactory(IGeneratorStreamSourceFactory<TMediaStreamSource> generatorStreamSourceFactory,
            Func<IAudioStreamSourceParameters, IEnumerable<float>> sourceFactory)
            : base(generatorStreamSourceFactory,
                streamParameters =>
                {
                    var source = sourceFactory(streamParameters);

                    if (streamParameters.Is16Bit)
                    {
                        return (position, buffer) =>
                        {
                            var i = 0;

                            foreach (var v in source)
                            {
                                if (i >= buffer.Length - 1)
                                    break;

                                var round = (int)Math.Round(short.MaxValue * v);

                                if (round > short.MaxValue)
                                    round = short.MaxValue;
                                else if (round < short.MinValue)
                                    round = short.MinValue;

                                buffer[i] = (byte)round;
                                buffer[i + 1] = (byte)(round >> 8);

                                i += 2;
                            }
                        };
                    }

                    return (position, buffer) =>
                    {
                        var i = 0;

                        foreach (var v in source)
                        {
                            if (i >= buffer.Length)
                                break;

                            var round = 128 + (int)Math.Round(127 * v);

                            if (round > 255)
                                round = 255;
                            else if (round < 0)
                                round = 0;

                            buffer[i++] = (byte)round;
                        }
                    };
                })
        { }
    }
}
